/*
 * Copyright (C) 2011 Reeny
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.tobidodo.spritmonclient;

import static de.tobidodo.spritmonclient.util.LogHelper.logInfo;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import de.tobidodo.spritmonclient.data.FuelDataDTO;
import de.tobidodo.spritmonclient.data.FuelDataPersister;
import de.tobidodo.spritmonclient.data.FuelDataProvider;
import de.tobidodo.spritmonclient.data.RequestParamDTO;
import de.tobidodo.spritmonclient.service.SendNewFuelDataService;
import de.tobidodo.spritmonclient.util.DialogHelper;
import de.tobidodo.spritmonclient.util.LogHelper;
import de.tobidodo.spritmonclient.util.RequestCallback;
import de.tobidodo.spritmonclient.util.RequestParamProvider;
import de.tobidodo.spritmonclient.util.TextUtil;

public class SpritMonitorClientActivity extends Activity implements RequestCallback{

	//private Handler msgHandler;

	/*private FuelDataPersister db;*/
	private Integer currentRowId;
	private AsyncTask<?, ?, ?> httpTransmission;
	ProgressDialog httpTransmitProgressDlg;



	/**
	 * Called when the activity is first created or when the
	 * system settings changed (orientation changed, language
	 * changed, etc).<p>
	 * Create the view and connect to the database for the
	 * fuel data. If this activity was already active before
	 * and is reloaded now the <code>savedInstanceState</code>
	 * contains the ID of the last edited fuel data. This data
	 * will be shown again. 
	 */
	@Override
	public void onCreate(final Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		logInfo("Spritmonitor Client started");

		setContentView(R.layout.main);

		setupButtons();
		
		/*connectToDatabase();*/

		reloadInterruptedFuelData(savedInstanceState);


	}



	@Override
	protected void onResume() {
		super.onResume();
		logInfo("RESUME");
	}

	@Override
	protected void onPause() {
		logInfo("PAUSE");
		super.onPause();
	}
	
	/**
	 * {@inheritDoc}
	 * Start the data base persister so that this activity
	 * has connection to the database.
	 */
	@Override
	protected void onStart() {
		super.onStart();
		logInfo("START");
		/*this.db.startFuelDataPersister();*/
	}

	/**
	 * {@inheritDoc}
	 * Stop the data base persister so that this activity
	 * has no connection anymore to the database.
	 */
	@Override
	protected void onStop() {
		logInfo("STOP");
		/*this.db.stopFuelDataPersister();*/
		if (this.httpTransmission != null){
			httpTransmission.cancel(false);
		}
		super.onStop();
	}

	/**
	 * {@inheritDoc}
	 * Save the database id and the textfield values of the
	 * current displayed fuel data in the <code>outState</code>
	 * object.
	 */
	@Override
	protected void onSaveInstanceState(final Bundle outState) {
		super.onSaveInstanceState(outState);

		logInfo("SAVE STATE");
		outState.putBoolean("state-saved", true);

		if (currentRowId != null){
			outState.putInt("dbid", currentRowId);
		}

		transferFormDataToBundle(outState);
	}



	/**
	 * {@inheritDoc}
	 * Reload the old state of this activity. If the given
	 * <code>savedInstanceState</code> contains a database id the
	 * data is loaded from the database. Otherwise if the
	 * <code>savedInstanceState</code> contains values for the
	 * textfields these are loaded.
	 */
	@Override
	protected void onRestoreInstanceState(final Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);
		logInfo("RESTORE STATE");
		if (savedInstanceState != null){
			int id = savedInstanceState.getInt("dbid", -1);

			currentRowId = (id == -1) ? null : Integer.valueOf(id);
			transferInterruptedDataToForm(savedInstanceState);
		}
	}



	@Override
	public boolean onCreateOptionsMenu(final Menu menu) {
		boolean parentResult = super.onCreateOptionsMenu(menu);
		
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.appmenu, menu);
		return parentResult && true;
	}

	@Override
	public boolean onOptionsItemSelected(final MenuItem item) {
		switch (item.getItemId()) {
		case R.id.settings:
			startSettingsUI();
			return true;
		case R.id.itemlistmenu:
			startDataListUI();
			return true;
		default:
			break;
		}
		return super.onOptionsItemSelected(item);
	}


	//####################################################################
	

	private void loadFormDataByFuelId(final int dataid) {
		currentRowId = (dataid == -1) ? null : Integer.valueOf(dataid);
		
		
		FuelDataDTO fuelEntry = (dataid == -1) ? FuelDataPersister.getLastFuelEntry(this) : FuelDataPersister.getFuelEntry(this, dataid);

		loadFormDataByFuelDataDTO(fuelEntry);
		updateStatusBarForEntry(fuelEntry);
	}


	private void loadFormDataByFuelDataDTO(final FuelDataDTO fueldata) {
		if (fueldata != null){
			currentRowId = fueldata.getCurrentDbId();
			updateCurrentDbIdLabel();
			setTotalDistanceFormValue(fueldata.getTotalDistanceValue());
			setPeriodDistanceFormValue(fueldata.getPeriodDistanceValue());
			setFuelAmountFormValue(fueldata.getFuelAmountValue());
			setFuelPriceFormValue(fueldata.getFuelPriceValue());
		}
		else{
			currentRowId = null;
			updateCurrentDbIdLabel();
			setTotalDistanceFormValue(null);
			setPeriodDistanceFormValue(null);
			setFuelAmountFormValue(null);
			setFuelPriceFormValue(null);
		}
	}
	
	
	
	private void reloadInterruptedFuelData(final Bundle savedInstanceState) {
		if (savedInstanceState != null && savedInstanceState.containsKey("state-saved")){
			logInfo("CREATE with saved state");
			int id = savedInstanceState.getInt("dbid", -1);
			loadFormDataByFuelId(id);

			if (id == -1){
				transferInterruptedDataToForm(savedInstanceState);
			}
		}
		else{
			logInfo("CREATE without saved state");
			loadFormDataByFuelId(-1);
		}
	}



	/*
	private void connectToDatabase() {
		db = new FuelDataPersister(SpritMonitorClientActivity.this);
		db.startFuelDataPersister();
	}
	*/

	/**
	 * Check if the current displayed fuel data is persisted
	 * in the database.
	 * @return <code>true</code> if the current displayed fuel
	 * 		data has a database id. <code>false</code> if the
	 * 		id is <code>null</code>.
	 */
	public boolean isNewData(){
		return currentRowId == null;
	}
	

	private void startSettingsUI(){
		Intent settingsActivity = new Intent(getBaseContext(), SpritmonitorClientPreferenceActivity.class);
		startActivity(settingsActivity);
	}
	
	private void startDataListUI(){
		Intent dataListActivity = new Intent(Intent.ACTION_VIEW, FuelDataProvider.CONTENT_LIST_URI);
		startActivity(dataListActivity);
	}



	private void setupButtons() {
		View saveBtn = findViewById(R.id.SaveAndTransmitDataButton);
		saveBtn.setOnClickListener(new SaveAndTransmitDataListener());

		View onlySaveBtn = findViewById(R.id.OnlySaveButton);
		onlySaveBtn.setOnClickListener(new OnlySaveDataListener());

		View createNewBtn = findViewById(R.id.NewEntryButton);
		createNewBtn.setOnClickListener(new CreateNewEntryListener());

		View prevBtn = findViewById(R.id.PrevEntryButton);
		prevBtn.setOnClickListener(new LoadPrevEntryListener());

		View nextBtn = findViewById(R.id.NextEntryButton);
		nextBtn.setOnClickListener(new LoadNextEntryListener());

	}




	private String getLoginUserNameFromPreferences(){
		SharedPreferences userSettings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
		return userSettings.getString(getString(R.string.pref_key_username), null);

	}

	private String getLoginUserPasswordFromPreferences(){
		SharedPreferences userSettings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
		return userSettings.getString(getString(R.string.pref_key_userpassword), null);
	} 



	private String getTotalDistanceFormValue(){
		View textfield = findViewById(R.id.EditTotalDistance);
		return ((EditText)textfield).getText().toString();
	}

	private void updateCurrentDbIdLabel(){
		View textfield = findViewById(R.id.CurDbIdText);
		((TextView)textfield).setText((currentRowId != null) ? currentRowId.toString() : "");
	}

	private void setTotalDistanceFormValue(final String value){
		View textfield = findViewById(R.id.EditTotalDistance);
		((EditText)textfield).setText(value);
	}

	private String getPeriodDistanceFormValue(){
		View textfield = findViewById(R.id.EditPeriodDistance);
		return ((EditText)textfield).getText().toString();
	}

	private void setPeriodDistanceFormValue(final String value){
		View textfield = findViewById(R.id.EditPeriodDistance);
		((EditText)textfield).setText(value);
	}

	private String getFuelAmountFormValue(){
		View textfield = findViewById(R.id.EditFuelEntry);
		return ((EditText)textfield).getText().toString();
	}

	private void setFuelAmountFormValue(final String value){
		View textfield = findViewById(R.id.EditFuelEntry);
		((EditText)textfield).setText(value);
	}

	private String getFuelPriceFormValue(){
		View textfield = findViewById(R.id.EditFuelPrice);
		return ((EditText)textfield).getText().toString();
	}

	private void setFuelPriceFormValue(final String value){
		View textfield = findViewById(R.id.EditFuelPrice);
		((EditText)textfield).setText(value);
	}

	private void setStatusLabelText(final int msgId){
		View statusLabel = findViewById(R.id.LabelStatusText);
		((TextView)statusLabel).setText(msgId);
	}

	private void setStatusLabelText(final String msg){
		View statusLabel = findViewById(R.id.LabelStatusText);
		((TextView)statusLabel).setText(msg);
	}


	private String getFuelTypeFromPreferences() {
		SharedPreferences userSettings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
		return userSettings.getString(getString(R.string.pref_key_ftype), null);
	}



	private FuelDataDTO asFuelDataDTO(){
		FuelDataDTO fuelData = new FuelDataDTO();

		fuelData.setCurrentDbId(currentRowId);
		fuelData.setTotalDistanceValue(getTotalDistanceFormValue());
		fuelData.setPeriodDistanceValue(getPeriodDistanceFormValue());
		fuelData.setFuelAmountValue(getFuelAmountFormValue());
		fuelData.setFuelPriceValue(getFuelPriceFormValue());

		return fuelData;
	}


	private RequestParamProvider asRequestParamDTO(){
		RequestParamDTO fuelData = new RequestParamDTO();

		fuelData.setTotalDistanceValue(this.getTotalDistanceFormValue());
		fuelData.setPeriodDistanceFormValue(this.getPeriodDistanceFormValue());
		fuelData.setFuelAmountFormValue(this.getFuelAmountFormValue());
		fuelData.setFuelPriceFormValue(this.getFuelPriceFormValue());
		fuelData.setFuelType(this.getFuelTypeFromPreferences());
		
		fuelData.setLoginUserName(this.getLoginUserNameFromPreferences());
		fuelData.setLoginUserPassword(this.getLoginUserPasswordFromPreferences());

		return fuelData;
	}
	

	private void clearStatusLabelText(){
		View statusLabel = findViewById(R.id.LabelStatusText);
		((TextView)statusLabel).setText(null);
	}


	private void updateStatusBarForEntry(final FuelDataDTO fuelEntry) {
		if (fuelEntry == null){
			setStatusLabelText(R.string.no_db_data_for_transmission);
		}
		else if (fuelEntry.getLastErrorId() != null){
			setStatusLabelText(fuelEntry.getLastErrorId());
		}
		else if (TextUtil.isNotEmpty(fuelEntry.getTransmittedTime())){
			setStatusLabelText("transm. at "+fuelEntry.getTransmittedTime());
		}
		else if (TextUtil.isNotEmpty(fuelEntry.getUpdatedTime())){
			setStatusLabelText("edited at "+fuelEntry.getUpdatedTime());
		}
		else{
			clearStatusLabelText();
		}
	}


	/**
	 * FIXME: need for what?!
	 */
	public void storeFormDataAndUpdateIdLabel(){
		FuelDataDTO fuelData = asFuelDataDTO();
		if (fuelData.isEmpty()){
			setStatusLabelText(R.string.empty_form_warning);
			return;
		}

		currentRowId = insertNewDataToDatabase(fuelData);
		updateCurrentDbIdLabel();
	}


	//####################################################################
	// HTTP transmission callbacks
	//####################################################################

	@Override
	public void onHttpTransmissionStarted(){
		//sendStateTextChange(R.string.transmission_running);
		Toast.makeText(this, R.string.transmission_running, Toast.LENGTH_SHORT);
		
		httpTransmitProgressDlg = ProgressDialog.show(this, "", "", true, true, new OnCancelListener() {
			
			@Override
			public void onCancel(DialogInterface dialog) {
				if (SpritMonitorClientActivity.this.httpTransmission != null){
					SpritMonitorClientActivity.this.httpTransmission.cancel(false);
				}
			}
		});
		/*
		View barView = findViewById(R.id.transmProgressBar);
		((ProgressBar)barView).setVisibility(View.VISIBLE);
		*/
	}

	@Override
	public void onProgressStateChanged(int progressValue){
		// FIXME: use progress bar
	}

	@Override
	public void postHttpSend(Integer transmitResultId, Throwable lastError){
		if (httpTransmitProgressDlg != null){
			httpTransmitProgressDlg.cancel();
			httpTransmitProgressDlg = null;
		}
		
		clearStatusLabelText();
		
		if (transmitResultId == 0){
			/*
			Intent notifyIntent = new Intent(this, NotifyFuelDataAsTransmitted.class);
			notifyIntent.putExtra(NotifyFuelDataAsTransmitted.ATTR_DB_ID, fuelDatabaseId);
			startService(notifyIntent);

    		boolean serviceIsBound = false;
    		ServiceConnection serviceCon = new NotifyFuelDataAsTransmittedConnection(SendNewFuelDataService.this);
    		Intent notifyIntent = new Intent(SendNewFuelDataService.this, SaveErrorMsgOfFuelData.class);
			notifyIntent.putExtra(SendNewFuelDataService.ATTR_DB_ID, fuelDatabaseId);
			notifyIntent.putExtra(SaveErrorMsgOfFuelData.ATTR_ERR_ID, transmitResultId);
			bindService(notifyIntent, serviceCon, Context.BIND_AUTO_CREATE);

			serviceIsBound = true;
			 */
			if (currentRowId != -1L){
				FuelDataPersister.updateTransmitDate(this, currentRowId);
				Toast.makeText(this, R.string.transmission_success, Toast.LENGTH_SHORT).show();
			}

			loadFormDataByFuelDataDTO(null);
		}
		else{
			if (lastError != null){
				LogHelper.logError("Failure while transmitting fuel data to spritmonitor.de", lastError);
				Toast.makeText(this, "Failure while transmitting fuel data to spritmonitor.de: "+lastError.toString(), Toast.LENGTH_LONG).show();
				lastError = null;
			}
			else{
				LogHelper.logInfo("Error id: "+transmitResultId);
				Toast.makeText(this, transmitResultId, Toast.LENGTH_LONG).show();
			}
		}

	}


	private void storeFormDataToDatabase() {
		FuelDataDTO formDataDTO = asFuelDataDTO();
		currentRowId = !isNewData() ? updateDataInDatabase(formDataDTO) : insertNewDataToDatabase(formDataDTO);
	}

	private Integer insertNewDataToDatabase(FuelDataDTO dto) {

		int resultId = FuelDataPersister.insert(this, TextUtil.getCurrentDate("yyyy-MM-dd"), dto);
		if (resultId == -1){
			return null;
		}

		return Integer.valueOf(resultId);
	}


	private Integer updateDataInDatabase(FuelDataDTO dto){
		int resultId = FuelDataPersister.update(this, TextUtil.getCurrentDate("yyyy-MM-dd"), dto);
		if (resultId == -1){
			return null;
		}

		return Integer.valueOf(resultId);
	}


	/*
	private void sendStateTextChange(final int resId){
		if (msgHandler == null){
			msgHandler = new Handler();
		}

		Message msg = msgHandler.obtainMessage();
		msg.arg2 = resId;
		msgHandler.sendMessage(msg);
	}
	*/



	private void transferFormDataToBundle(final Bundle outState) {
		outState.putString("total-dist", getTotalDistanceFormValue());
		outState.putString("last-dist", getPeriodDistanceFormValue());
		outState.putString("fuel-input", getFuelAmountFormValue());
		outState.putString("fuel-price", getFuelPriceFormValue());
	}

	private void transferInterruptedDataToForm(final Bundle savedInstanceState) {
		setTotalDistanceFormValue(savedInstanceState.getString("total-dist"));
		setPeriodDistanceFormValue(savedInstanceState.getString("last-dist"));
		setFuelAmountFormValue(savedInstanceState.getString("fuel-input"));
		setFuelPriceFormValue(savedInstanceState.getString("fuel-price"));
	}







	// #############################################


	private final class LoadPrevEntryListener implements View.OnClickListener{
		@Override
		public void onClick(final View v) {

			FuelDataDTO prevEntryData = null;

			if (currentRowId == null){
				prevEntryData = FuelDataPersister.getLastFuelEntry(SpritMonitorClientActivity.this);
				if (prevEntryData == null){
					return;
				}
			}
			else{	
				prevEntryData = FuelDataPersister.getPrevFuelEntry(SpritMonitorClientActivity.this, currentRowId);
			}

			if (prevEntryData == null){
				Dialog dlg = DialogHelper.createErrorDialog(SpritMonitorClientActivity.this, R.string.no_prev_entry);
				dlg.show();
				return;
			}

			clearStatusLabelText();

			if (prevEntryData != null){
				loadFormDataByFuelDataDTO(prevEntryData);
			}
		}
	}

	private final class LoadNextEntryListener implements View.OnClickListener{
		@Override
		public void onClick(final View v) {

			FuelDataDTO nextEntryData = null;

			if (currentRowId == null){
				nextEntryData = FuelDataPersister.getLastFuelEntry(SpritMonitorClientActivity.this);
				if (nextEntryData == null){
					return;
				}
			}
			else{
				nextEntryData = FuelDataPersister.getNextFuelEntry(SpritMonitorClientActivity.this, currentRowId);
			}

			if (nextEntryData == null){
				AlertDialog dlg = DialogHelper.createErrorDialog(SpritMonitorClientActivity.this, R.string.no_next_entry);
				dlg.show();
				return;
			}

			clearStatusLabelText();

			loadFormDataByFuelDataDTO(nextEntryData);

		}
	}

	private final class CreateNewEntryListener implements View.OnClickListener{
		@Override
		public void onClick(final View v) {
			loadFormDataByFuelDataDTO(null);
			clearStatusLabelText();
		}
	}

	private class OnlySaveDataListener implements OnClickListener {

		@Override
		public void onClick(final View v) {
			clearStatusLabelText();

			if (asFuelDataDTO().isEmpty()){
				setStatusLabelText(R.string.empty_form_warning);
				return;
			}

			storeFormDataToDatabase();
			setStatusLabelText(R.string.save_success);
			updateCurrentDbIdLabel();
		}

	}

	private final class SaveAndTransmitDataListener implements View.OnClickListener {
		@Override
		public void onClick(final View v) {
			clearStatusLabelText();

			if (asFuelDataDTO().isEmpty()){
				setStatusLabelText(R.string.empty_form_warning);
				return;
			}

			storeFormDataToDatabase();
			setStatusLabelText(R.string.save_success);
			updateCurrentDbIdLabel();


			try{
				httpTransmission = new SendNewFuelDataService(SpritMonitorClientActivity.this).execute(asRequestParamDTO());
			}catch(Exception exc){
				Dialog dlg = DialogHelper.createErrorDialog(SpritMonitorClientActivity.this, "Error while starting data transmission: "+exc.toString());
				dlg.show();
			}


		}


	}




}